/* vcc/main.c 
 * 
 * This file is part of vcc. 
 * 
 * vcc is free software: you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License as published by 
 * the Free Software Foundation, either version 3 of the License, or 
 * (at your option) any later version. 
 * 
 * vcc is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
 * GNU General Public License for more details. 
 * 
 * You should have received a copy of the GNU General Public License 
 * along with vcc. If not, see <https://www.gnu.org/licenses/>
 */ 




#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <locale.h>

#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <poll.h>
#include <signal.h>

#include <vcc/vcc.h>
#include <vcc/version.h>
#include <vcc/pretty.h>

#define DEFAULT_RATE 	1000


int send_msg(const char *msg, const char *usrname);
int read_msg(struct vcc_request *buf);
int get_msgs(void);
int vcc_login(char *, char *);

int do_cmd(char *s);
int do_bh(struct vcc_request *);

int init_socket(const char *server_addr, int server_port);


int fd;
int rate;

char usrname[USRNAME_SIZE];

extern int current_sid;

static char const *help_msg = {
	"Usage: vcc [-up] [server]\n"
	"Options: \n"
	"  -u    --user    Set the username on the server. "
	"If unspecified, you must input it interatively. \n"
	"  -p    --port    Specified the port on the server. "
	"Default port is 46. You must keep this as same "
	"as the port on the server. \n"
	"  [server]        Address of the server. "
	"As default, server is 124.223.105.230. \n"
};

static int usage(void) {
	fprintf(stderr, help_msg);

	return 1;
}


static int login(int got_usrname) {
	char *passwd;
	if (!got_usrname) {
		fprintf(stderr, "login as: ");
		scanf("%s", usrname);
	}

	passwd = getpass("password: ");

	vcc_login(usrname, passwd);

	return 0;
}

int parse_args(char **argv, int *port, char **ip) {
	int i = 1;
	/*
	 * unknown: 0
	 * usrname: 1
	 * port: 2
	 */
	int type = 0;
	int got_usrname = 0;
	char *arg;

	while (argv[i]) {
		arg = argv[i];
		switch (type) {
		case 0:
			if (!strcmp(arg, "-u") || !strcmp(arg, "--user")) {
				type = 1;
			} else if (!strcmp(arg, "-p") || !strcmp(arg, "--port")) {
				type = 2;
			} else if (arg[0] != '-') {
				*ip = arg;
			} else {
				exit(usage());
			}
			break;
		case 1:
			printf("%s %s\n", arg, usrname);
			strcpy(usrname, arg);
			got_usrname = 1;
			type = 0;
			break;
		case 2:
			*port = atoi(arg);
			type = 0;
			break;
		default:
			abort();
		}
		++i;
	}
	return got_usrname;
}


int main(int argc, char **argv) {
	struct pollfd 		fds[2];
	struct vcc_request 	*req;
	char 			*buf, *msg, *ip = "124.223.105.230";
	int 			n, size, port = VCC_PORT, got_usrname;
	(void) argc;

#ifdef _WIN32
	setlocale(LC_ALL, ".UTF-8");
#else
	setlocale(LC_ALL, "C.UTF-8");
#endif

	printf(VCC_VERSION "\n");

	got_usrname = parse_args(argv, &port, &ip);
	init_socket(ip, port);

	printf("Connected to server. \n");
	printf("%s@%s%d\n", usrname, ip, port);

	login(got_usrname);

	fds[0].fd = 0;
	fds[0].events = POLLIN;
	fds[0].revents = 0;

	fds[1].fd = fd;
	fds[1].events = POLLIN;
	fds[1].revents = 0;

	rate = DEFAULT_RATE;

	if (unlikely(!(buf = malloc(MSG_SIZE)))) {
		fprintf(stderr, "*** malloc() failed\n");

		return 1;
	}

	if (unlikely(!(req = malloc(REQ_SIZE)))) {
		fprintf(stderr, "*** malloc() failed\n");

		return 1;
	}

	for (;;) {
		n = poll(fds, 2, rate);

		if (n == -1) {
			if (likely(errno == EINTR)) 
				continue;

			perror("poll()");

			break;
		}

		if (!n) {
			/* 1 sec timed out */

			get_msgs();

			continue;
		}

		if (fds[0].revents & POLLIN) {
			/* read keyboard */

			memset(buf, 0, MSG_SIZE);

			if (read(0, buf, MSG_SIZE) < 0) {
				perror("read()");

				continue;
			}

			if (*buf == '-') 
				do_cmd(buf);

			else if (*buf != '\n') {
				send_msg(buf, usrname);

				pretty_new_msg(usrname, buf, current_sid);
			}

			pretty_prompt(usrname);
		}

		if (fds[1].revents & POLLIN) {
			size = read(fd, req, REQ_SIZE);

			if (unlikely(!size)) {
				fprintf(stderr, "Server closed. \n");

				break;
			}

			if (ntohl(req->reqtype) != REQ_MSG_NEW) {
				do_bh(req);

				continue;
			}

			msg = req->msg;

			if (!*msg || *(unsigned char *) msg == 0xffu) 
				continue;

			pretty_new_msg(req->usrname, msg, ntohl(req->session));
			pretty_prompt(usrname);
		}
	}

	printf("bye. \n");

	return 0;
}

